# -*- coding: utf-8 -*-
"""
系统工具模块 - 系统级功能如单实例、开机启动、环境设置等
"""
__all__ = ['get_idle_seconds', 'setup_environment', 'safe_exit']# 允许别的模块调用

import os
import sys
import ctypes
from ctypes import wintypes
import winreg
import subprocess
import psutil
import shutil
import threading
import time
import atexit
import signal
from pathlib import Path
from git_sync import GitSyncManager
import datetime
from services.state_manager import state, start
from services.file_operations import _LOCKED_FILES
from services.state_manager import _update_last_record_end_time
from utils.logger import log
from services.state_manager import _GUARD_EXIT
from utils.constants import (
    EXIT_PWD, GIT_SYNC_INTERVAL, STATE_MAP, STATE_COLOR, WORK_STATES,
    ROLE_MAP, GRACE_SECS, MUTEX_NAME
)

_hMutex = None

def check_first_run(data_dir):
    """检查是否是第一次运行"""
    first_run_file = os.path.join(data_dir, '.first_run')
    if not os.path.exists(first_run_file):
        with open(first_run_file, 'w') as f:
            f.write('1')
        return True
    return False

def set_data_dir(data_dir): 
    global _DATA_DIR
    _DATA_DIR = data_dir
    
def setup_environment(): #环境设置（重要）
    """单文件/多文件模式智能复制自身到 D 盘并重启"""

    print('[DEBUG] 开始执行环境设置...')
    try:
        exe_path = os.path.abspath(sys.executable)
        exe_name = os.path.splitext(os.path.basename(exe_path))[0]
        print(f'[DEBUG] 程序名称: {exe_name}')
        
        # D盘数据目录
        d_drive_dir = os.path.join('D:\\', f'{exe_name}_Data')
        os.makedirs(d_drive_dir, exist_ok=True)
        
        # 单文件打包时，源目录就是临时解压目录
        if getattr(sys, 'frozen', False):
            if hasattr(sys, '_MEIPASS'):
                # 单文件模式，使用临时解压目录作为源目录
                source_dir = sys._MEIPASS
                print(f'[DEBUG] 单文件模式，临时目录: {source_dir}')
            else:
                # 单目录模式
                source_dir = os.path.dirname(exe_path)
        else:
            # 开发模式
            source_dir = os.path.dirname(os.path.abspath(__file__))
        
        # 需要复制的配置文件和资源
        items_to_copy = [
            'config.ini',     # 配置文件
        ]
        
        # 复制必要文件到D盘目录
        for item in items_to_copy:
            source_path = os.path.join(source_dir, item)
            dest_path = os.path.join(d_drive_dir, item)
            
            # 如果源文件存在且目标文件不存在，才复制
            if os.path.exists(source_path) and not os.path.exists(dest_path):
                if os.path.isdir(source_path):
                    print(f'[INFO] 复制目录: {item}')
                    shutil.copytree(source_path, dest_path)
                else:
                    print(f'[INFO] 复制文件: {item}')
                    shutil.copy2(source_path, dest_path)
            else:
                print(f'[INFO] 跳过复制: {item}')
        
        # 预建常用子目录
        log_dir = os.path.join(d_drive_dir, 'logs')
        os.makedirs(log_dir, exist_ok=True)
        print('[DEBUG] 数据目录创建完成')
        
        # 设置现有Excel文件为只读
        for filename in os.listdir(d_drive_dir):
            if filename.lower().endswith(('.xlsx', '.xls')):
                excel_path = os.path.join(d_drive_dir, filename)
                try:
                    import stat
                    os.chmod(excel_path, stat.S_IREAD)
                    print(f'[INFO] 已设置 {filename} 为只读模式')
                except Exception as e:
                    print(f'[WARN] 设置 {filename} 为只读失败: {e}')
        
        # 检查是否需要复制EXE文件（单文件模式不需要）
        target_exe_path = os.path.join(d_drive_dir, f'{exe_name}.exe')
        
        # 单文件模式：如果当前不在D盘运行，启动D盘版本并完全退出
        target_exe_path = os.path.join(d_drive_dir, f'{exe_name}.exe')
        if getattr(sys, 'frozen', False) and os.path.abspath(exe_path).lower() != os.path.abspath(target_exe_path).lower():
            print(f'[INFO] 单文件模式，准备重启到D盘: {target_exe_path}')
            try:
                # 复制当前EXE到D盘（如果不存在或版本不同）
                need_copy = True
                if os.path.exists(target_exe_path):
                    # 比较文件大小和修改时间来判断是否需要更新
                    src_stat = os.stat(exe_path)
                    dst_stat = os.stat(target_exe_path)
                    if src_stat.st_size == dst_stat.st_size and src_stat.st_mtime <= dst_stat.st_mtime:
                        need_copy = False
                        print('[INFO] D盘EXE已是最新，跳过复制')
                
                if need_copy:
                    print('[INFO] 复制EXE到D盘数据目录...')
                    shutil.copy2(exe_path, target_exe_path)
                    print(f'[INFO] EXE已复制到: {target_exe_path}')
                
                # 启动D盘版本
                print('[INFO] 启动D盘版本...')
                subprocess.Popen([target_exe_path], 
                               cwd=d_drive_dir,  # 设置工作目录
                               creationflags=subprocess.CREATE_NO_WINDOW)
                
                print('[INFO] 已启动D盘EXE，当前进程即将退出')
                # 完全退出当前进程
                sys.exit(0)
                
            except Exception as e:
                print(f'[WARN] 无法启动D盘EXE: {e}')
                print('[INFO] 将继续使用当前EXE运行')
                return d_drive_dir
        else:
            print('[INFO] 当前已在D盘运行，继续执行')
            return d_drive_dir
        
        return d_drive_dir
        
    except Exception as e:
        print(f'[ERR] 环境设置失败: {e}')
        import traceback
        traceback.print_exc()
        # 单文件模式回退到临时目录
        if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
            return sys._MEIPASS
        else:
            return os.path.dirname(os.path.abspath(sys.executable))

def check_single_instance(): #单实例检查
    """全局互斥体防多开"""
    global _hMutex
    try:
        _hMutex = ctypes.windll.kernel32.OpenMutexW(0x1F0001, False, MUTEX_NAME)
        if _hMutex:
            ctypes.windll.kernel32.CloseHandle(_hMutex)
            ctypes.windll.user32.MessageBoxW(0, '程序已在运行!', '提示', 0)
            sys.exit()
        _hMutex = ctypes.windll.kernel32.CreateMutexW(None, False, MUTEX_NAME)
    except Exception as e:
        print(f'[WARN] 单实例检查失败: {e}')

def release_mutex(): #释放互斥体
    """释放单例互斥体，允许新实例立即启动"""
    global _hMutex
    if _hMutex:
        ctypes.windll.kernel32.ReleaseMutex(_hMutex)
        ctypes.windll.kernel32.CloseHandle(_hMutex)
        _hMutex = None
        log('[MUTEX] 已主动释放互斥体')

def ensure_early_startup(): #设置开机启动
    """写注册表 + 计划任务实现“登录即启”"""
    global _DATA_DIR
    if _DATA_DIR is None:
        log('[WARN] _DATA_DIR 未设置，跳过开机启动设置')
        return
        
    exe_path = os.path.join(_DATA_DIR, os.path.basename(sys.executable))
    task_name = "TrackerEarly"
    # 关键改动：ONLOGON + 当前登录用户
    cmd = [
        "schtasks", "/create",
        "/tn", task_name,
        "/tr", f'"{exe_path}"',
        "/sc", "ONLOGON",              # ← 用户登录时触发
        "/ru", os.environ["USERNAME"], # ← 当前用户会话，托盘可见
        "/rl", "HIGHEST",
        "/delay", "0000:00",           # ← 立即运行
        "/f"
    ]
    try:
        subprocess.run(cmd, check=True, capture_output=True, creationflags=subprocess.CREATE_NO_WINDOW)
        log(f'[INFO] 任务计划 {task_name} 已创建（登录即启动，托盘可见）')
    except subprocess.CalledProcessError as e:
        log(f'[WARN] 创建任务计划失败: {e.stderr.decode("gbk", errors="ignore")}')
    except Exception as e:
        log(f'[WARN] 无法创建任务计划: {e}')

# 在 system_utils.py 的 safe_exit 函数开头添加
def safe_exit(icon=None):
    """只落盘，不杀进程 - 添加安全检查"""
    import traceback
    log('[SAFE-EXIT] 程序退出 - 开始')
    
    # 检查是否在子线程中调用
    if threading.current_thread() != threading.main_thread():
        log('[SAFE-EXIT] 警告: 在子线程中调用 safe_exit')
        return
    
    # 添加调用堆栈信息（调试用）
    stack = traceback.extract_stack()
    if len(stack) > 2:  # 避免空堆栈
        caller_info = []
        for frame in stack[-4:-1]:  # 取最近几个调用帧
            caller_info.append(f"{os.path.basename(frame.filename)}:{frame.lineno}")
        
        log(f'[SAFE-EXIT] 调用来源: {" <- ".join(caller_info)}')
    
    try:
        # 1. 落盘
        from services.state_manager import state, start
        if start and state is not None:
            now = datetime.datetime.now()
            from services.state_manager import _update_last_record_end_time
            _update_last_record_end_time(now)
        
        # 2. 放锁
        from services.file_operations import release_all_locks
        release_all_locks()
        
    except Exception as e:
        log(f'[SAFE-EXIT] 退出清理失败: {e}')
    
    log('[SAFE-EXIT] 程序退出 - 完成')
    # 重要：不要调用 os._exit(0) 或其他退出函数

def sync_worker(mgr: GitSyncManager) -> None:    
    log(f'[SYNC] 定时推送已启动，周期：{GIT_SYNC_INTERVAL // 60} 分钟')      
    while True:
        time.sleep(GIT_SYNC_INTERVAL)                
        if mgr.enabled and mgr.ready()[0]:
            ok = mgr.sync()
            log(f'[SYNC] {"完成" if ok else "失败"}')

def verify_password(action_name: str) -> bool: #验证密码-退出/切换账户前弹框
    """验证退出/切换等操作的密码"""

    from utils.input_dialogs import input_box
    from utils.constants import EXIT_PWD
    try:
        pwd = input_box('密码验证', f'请输入密码以{action_name}:', mask=True)
        return pwd == EXIT_PWD
    except Exception:
        return False

def create_logon_task_xml():
    """创建 TrackerEarly 登录任务计划（含工作目录），失败不抛异常，只记录"""
    global _DATA_DIR
    if _DATA_DIR is None:
        log('[WARN] _DATA_DIR 未设置，跳过XML任务创建')
        return
        
    import tempfile

    xml_str = r'''<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Description>Tracker logon startup with working directory</Description>
  </RegistrationInfo>
  <Triggers>
    <LogonTrigger><Enabled>true</Enabled></LogonTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <LogonType>InteractiveToken</LogonType>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>"{exe}"</Command>
      <WorkingDirectory>{wd}</WorkingDirectory>
    </Exec>
  </Actions>
</Task>'''.format(exe=os.path.join(_DATA_DIR, os.path.basename(sys.executable)),
                  wd=_DATA_DIR)

    try:
        with tempfile.NamedTemporaryFile(mode='w', suffix='.xml', delete=False, encoding='utf-16') as f:
            f.write(xml_str)
            tmp_xml = f.name

        subprocess.run([
            'schtasks', '/create', '/tn', 'TrackerEarly',
            '/xml', tmp_xml, '/f'
        ], check=True, capture_output=True)
        log('[BOOT] 登录任务 TrackerEarly 已创建/更新')
    except Exception as e:
        log(f'[BOOT] 创建登录任务失败: {e}')
    finally:
        if 'tmp_xml' in locals():
            os.remove(tmp_xml)

def verify_and_clean_old_files():
    """验证版本并清理旧文件"""
    if _DATA_DIR is None:
        log('[WARN] _DATA_DIR 为 None，跳过版本验证')
        return
    try:
        current_dir = Path(_DATA_DIR)
        
        # 查找并删除.old备份文件
        for old_file in current_dir.glob("*.old"):
            try:
                old_file.unlink()
                log(f'[CLEAN] 已删除旧文件: {old_file.name}')
            except:
                pass
                
        # 直接使用 constants.py 中的版本号
        from utils.constants import VERSION
        log(f'[INFO] 当前运行版本: {VERSION}')
        
    except Exception as e:
        log(f'[ERR] 版本验证失败: {e}')

def _start_updater_and_exit():
    """启动升级器并强制退出当前进程，确保新实例不会被互斥体挡住"""
    try:
        log('[UPD] 升级器准备启动，主进程即将自杀...')
        # 1. 先释放互斥体
        release_mutex()
        # 2. 强制结束自己（不留托盘/浮窗）
        os.kill(os.getpid(), getattr(signal, 'SIGTERM', 15))
    except Exception as e:
        log(f'[ERR] 自杀失败: {e}')
        # 兜底：直接 _exit
        os._exit(0)
